// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/tools/quic/quic_simple_server_stream.h"

#include <utility>

#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_utils.h"
#include "net/quic/spdy_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
#include "net/test/gtest_util.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_simple_server_session.h"
#include "net/tools/quic/spdy_balsa_utils.h"
#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

using base::StringPiece;
using net::test::kInitialSessionFlowControlWindowForTest;
using net::test::kInitialStreamFlowControlWindowForTest;
using net::test::MockQuicConnection;
using net::test::MockQuicConnectionHelper;
using net::test::MockQuicSpdySession;
using net::test::ReliableQuicStreamPeer;
using net::test::SupportedVersions;
using std::string;
using testing::_;
using testing::AnyNumber;
using testing::InSequence;
using testing::Invoke;
using testing::InvokeArgument;
using testing::Return;
using testing::StrictMock;
using testing::WithArgs;

namespace net {
namespace test {

    class QuicSimpleServerStreamPeer : public QuicSimpleServerStream {
    public:
        QuicSimpleServerStreamPeer(QuicStreamId stream_id, QuicSpdySession* session)
            : QuicSimpleServerStream(stream_id, session)
        {
        }

        ~QuicSimpleServerStreamPeer() override {};

        using QuicSimpleServerStream::SendErrorResponse;
        using QuicSimpleServerStream::SendResponse;

        SpdyHeaderBlock* mutable_headers() { return &request_headers_; }

        static void SendResponse(QuicSimpleServerStream* stream)
        {
            stream->SendResponse();
        }

        static void SendErrorResponse(QuicSimpleServerStream* stream)
        {
            stream->SendErrorResponse();
        }

        static const string& body(QuicSimpleServerStream* stream)
        {
            return stream->body_;
        }

        static int content_length(QuicSimpleServerStream* stream)
        {
            return stream->content_length_;
        }

        static SpdyHeaderBlock& headers(QuicSimpleServerStream* stream)
        {
            return stream->request_headers_;
        }
    };

    class MockQuicSimpleServerSession : public QuicSimpleServerSession {
    public:
        const size_t kMaxStreamsForTest = 100;

        explicit MockQuicSimpleServerSession(
            QuicConnection* connection,
            MockQuicServerSessionVisitor* owner,
            MockQuicServerSessionHelper* helper,
            QuicCryptoServerConfig* crypto_config,
            QuicCompressedCertsCache* compressed_certs_cache)
            : QuicSimpleServerSession(DefaultQuicConfig(),
                connection,
                owner,
                helper,
                crypto_config,
                compressed_certs_cache)
        {
            set_max_open_incoming_streams(kMaxStreamsForTest);
            set_max_open_outgoing_streams(kMaxStreamsForTest);
            ON_CALL(*this, WritevData(_, _, _, _, _, _))
                .WillByDefault(testing::Return(QuicConsumedData(0, false)));
        }

        ~MockQuicSimpleServerSession() override { }

        MOCK_METHOD3(OnConnectionClosed,
            void(QuicErrorCode error,
                const string& error_details,
                ConnectionCloseSource source));
        MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id));
        MOCK_METHOD6(WritevData,
            QuicConsumedData(ReliableQuicStream* stream,
                QuicStreamId id,
                QuicIOVector data,
                QuicStreamOffset offset,
                bool fin,
                QuicAckListenerInterface*));
        MOCK_METHOD2(OnStreamHeaders,
            void(QuicStreamId stream_id, StringPiece headers_data));
        MOCK_METHOD2(OnStreamHeadersPriority,
            void(QuicStreamId stream_id, SpdyPriority priority));
        MOCK_METHOD3(OnStreamHeadersComplete,
            void(QuicStreamId stream_id, bool fin, size_t frame_len));
        // Methods taking non-copyable types like SpdyHeaderBlock by value cannot be
        // mocked directly.
        size_t WriteHeaders(
            QuicStreamId id,
            SpdyHeaderBlock headers,
            bool fin,
            SpdyPriority priority,
            QuicAckListenerInterface* ack_notifier_delegate) override
        {
            return WriteHeadersMock(id, headers, fin, priority, ack_notifier_delegate);
        }
        MOCK_METHOD5(WriteHeadersMock,
            size_t(QuicStreamId id,
                const SpdyHeaderBlock& headers,
                bool fin,
                SpdyPriority priority,
                QuicAckListenerInterface* ack_notifier_delegate));
        MOCK_METHOD3(SendRstStream,
            void(QuicStreamId stream_id,
                QuicRstStreamErrorCode error,
                QuicStreamOffset bytes_written));
        MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
        // Matchers cannot be used on non-copyable types like SpdyHeaderBlock.
        void PromisePushResources(
            const string& request_url,
            const std::list<QuicInMemoryCache::ServerPushInfo>& resources,
            QuicStreamId original_stream_id,
            const SpdyHeaderBlock& original_request_headers) override
        {
            original_request_headers_ = original_request_headers.Clone();
            PromisePushResourcesMock(request_url, resources, original_stream_id,
                original_request_headers);
        }
        MOCK_METHOD4(PromisePushResourcesMock,
            void(const string&,
                const std::list<QuicInMemoryCache::ServerPushInfo>&,
                QuicStreamId,
                const SpdyHeaderBlock&));

        using QuicSession::ActivateStream;

        SpdyHeaderBlock original_request_headers_;

    private:
        DISALLOW_COPY_AND_ASSIGN(MockQuicSimpleServerSession);
    };

    namespace {

        class QuicSimpleServerStreamTest
            : public ::testing::TestWithParam<QuicVersion> {
        public:
            QuicSimpleServerStreamTest()
                : connection_(
                    new StrictMock<MockQuicConnection>(&helper_,
                        &alarm_factory_,
                        Perspective::IS_SERVER,
                        SupportedVersions(GetParam())))
                , crypto_config_(new QuicCryptoServerConfig(
                      QuicCryptoServerConfig::TESTING,
                      QuicRandom::GetInstance(),
                      ::net::test::CryptoTestUtils::ProofSourceForTesting()))
                , compressed_certs_cache_(
                      QuicCompressedCertsCache::kQuicCompressedCertsCacheSize)
                , session_(connection_,
                      &session_owner_,
                      &session_helper_,
                      crypto_config_.get(),
                      &compressed_certs_cache_)
                , body_("hello world")
            {
                FLAGS_quic_always_log_bugs_for_tests = true;
                SpdyHeaderBlock request_headers;
                request_headers[":host"] = "";
                request_headers[":authority"] = "www.google.com";
                request_headers[":path"] = "/";
                request_headers[":method"] = "POST";
                request_headers[":version"] = "HTTP/1.1";
                request_headers["content-length"] = "11";

                headers_string_ = net::SpdyUtils::SerializeUncompressedHeaders(request_headers);

                // New streams rely on having the peer's flow control receive window
                // negotiated in the config.
                session_.config()->SetInitialStreamFlowControlWindowToSend(
                    kInitialStreamFlowControlWindowForTest);
                session_.config()->SetInitialSessionFlowControlWindowToSend(
                    kInitialSessionFlowControlWindowForTest);
                stream_ = new QuicSimpleServerStreamPeer(::net::test::kClientDataStreamId1,
                    &session_);
                // Register stream_ in dynamic_stream_map_ and pass ownership to session_.
                session_.ActivateStream(stream_);

                QuicInMemoryCachePeer::ResetForTests();
            }

            ~QuicSimpleServerStreamTest() override
            {
                QuicInMemoryCachePeer::ResetForTests();
            }

            const string& StreamBody()
            {
                return QuicSimpleServerStreamPeer::body(stream_);
            }

            StringPiece StreamHeadersValue(const string& key)
            {
                return (*stream_->mutable_headers())[key];
            }

            SpdyHeaderBlock response_headers_;
            MockQuicConnectionHelper helper_;
            MockAlarmFactory alarm_factory_;
            StrictMock<MockQuicConnection>* connection_;
            StrictMock<MockQuicServerSessionVisitor> session_owner_;
            StrictMock<MockQuicServerSessionHelper> session_helper_;
            std::unique_ptr<QuicCryptoServerConfig> crypto_config_;
            QuicCompressedCertsCache compressed_certs_cache_;
            StrictMock<MockQuicSimpleServerSession> session_;
            QuicSimpleServerStreamPeer* stream_; // Owned by session_.
            string headers_string_;
            string body_;
        };

        INSTANTIATE_TEST_CASE_P(Tests,
            QuicSimpleServerStreamTest,
            ::testing::ValuesIn(QuicSupportedVersions()));

        TEST_P(QuicSimpleServerStreamTest, TestFraming)
        {
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(AnyNumber())
                .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
            stream_->OnStreamHeaders(headers_string_);
            stream_->OnStreamHeadersComplete(false, headers_string_.size());
            stream_->OnStreamFrame(
                QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_));
            EXPECT_EQ("11", StreamHeadersValue("content-length"));
            EXPECT_EQ("/", StreamHeadersValue(":path"));
            EXPECT_EQ("POST", StreamHeadersValue(":method"));
            EXPECT_EQ(body_, StreamBody());
        }

        TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket)
        {
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(AnyNumber())
                .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));

            stream_->OnStreamHeaders(headers_string_);
            stream_->OnStreamHeadersComplete(false, headers_string_.size());
            stream_->OnStreamFrame(
                QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_));
            EXPECT_EQ("11", StreamHeadersValue("content-length"));
            EXPECT_EQ("/", StreamHeadersValue(":path"));
            EXPECT_EQ("POST", StreamHeadersValue(":method"));
            EXPECT_EQ(body_, StreamBody());
        }

        TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading)
        {
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(AnyNumber())
                .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));

            EXPECT_FALSE(stream_->fin_received());
            EXPECT_FALSE(stream_->rst_received());

            stream_->set_fin_sent(true);
            stream_->CloseWriteSide();

            if (GetParam() > QUIC_VERSION_28) {
                EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
            } else {
                EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
            }
            stream_->StopReading();
        }

        TEST_P(QuicSimpleServerStreamTest, TestFramingExtraData)
        {
            string large_body = "hello world!!!!!!";

            // We'll automatically write out an error (headers + body)
            EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .WillOnce(Invoke(MockQuicSession::ConsumeAllData));
            EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);

            stream_->OnStreamHeaders(headers_string_);
            stream_->OnStreamHeadersComplete(false, headers_string_.size());
            stream_->OnStreamFrame(
                QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_));
            // Content length is still 11.  This will register as an error and we won't
            // accept the bytes.
            stream_->OnStreamFrame(
                QuicStreamFrame(stream_->id(), /*fin=*/true, body_.size(), large_body));
            EXPECT_EQ("11", StreamHeadersValue("content-length"));
            EXPECT_EQ("/", StreamHeadersValue(":path"));
            EXPECT_EQ("POST", StreamHeadersValue(":method"));
        }

        TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus)
        {
            // Send an illegal response with response status not supported by HTTP/2.
            SpdyHeaderBlock* request_headers = stream_->mutable_headers();
            (*request_headers)[":path"] = "/bar";
            (*request_headers)[":authority"] = "www.google.com";
            (*request_headers)[":version"] = "HTTP/1.1";
            (*request_headers)[":method"] = "GET";

            response_headers_[":version"] = "HTTP/1.1";
            // HTTP/2 only supports integer responsecode, so "200 OK" is illegal.
            response_headers_[":status"] = "200 OK";
            response_headers_["content-length"] = "5";
            string body = "Yummm";
            QuicInMemoryCache::GetInstance()->AddResponse(
                "www.google.com", "/bar", std::move(response_headers_), body);

            stream_->set_fin_received(true);

            InSequence s;
            EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, nullptr));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(1)
                .WillOnce(Return(QuicConsumedData(
                    strlen(QuicSimpleServerStream::kErrorResponseBody), true)));

            QuicSimpleServerStreamPeer::SendResponse(stream_);
            EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
            EXPECT_TRUE(stream_->reading_stopped());
            EXPECT_TRUE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus2)
        {
            // Send an illegal response with response status not supported by HTTP/2.
            SpdyHeaderBlock* request_headers = stream_->mutable_headers();
            (*request_headers)[":path"] = "/bar";
            (*request_headers)[":authority"] = "www.google.com";
            (*request_headers)[":version"] = "HTTP/1.1";
            (*request_headers)[":method"] = "GET";

            response_headers_[":version"] = "HTTP/1.1";
            // HTTP/2 only supports 3-digit-integer, so "+200" is illegal.
            response_headers_[":status"] = "+200";
            response_headers_["content-length"] = "5";
            string body = "Yummm";
            QuicInMemoryCache::GetInstance()->AddResponse(
                "www.google.com", "/bar", std::move(response_headers_), body);

            stream_->set_fin_received(true);

            InSequence s;
            EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, nullptr));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(1)
                .WillOnce(Return(QuicConsumedData(
                    strlen(QuicSimpleServerStream::kErrorResponseBody), true)));

            QuicSimpleServerStreamPeer::SendResponse(stream_);
            EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
            EXPECT_TRUE(stream_->reading_stopped());
            EXPECT_TRUE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest, SendPushResponseWith404Response)
        {
            // Create a new promised stream with even id().
            QuicSimpleServerStreamPeer* promised_stream = new QuicSimpleServerStreamPeer(2, &session_);
            session_.ActivateStream(promised_stream);

            // Send a push response with response status 404, which will be regarded as
            // invalid server push response.
            SpdyHeaderBlock* request_headers = promised_stream->mutable_headers();
            (*request_headers)[":path"] = "/bar";
            (*request_headers)[":authority"] = "www.google.com";
            (*request_headers)[":version"] = "HTTP/1.1";
            (*request_headers)[":method"] = "GET";

            response_headers_[":version"] = "HTTP/1.1";
            response_headers_[":status"] = "404";
            response_headers_["content-length"] = "8";
            string body = "NotFound";
            QuicInMemoryCache::GetInstance()->AddResponse(
                "www.google.com", "/bar", std::move(response_headers_), body);

            InSequence s;
            EXPECT_CALL(session_,
                SendRstStream(promised_stream->id(), QUIC_STREAM_CANCELLED, 0));

            QuicSimpleServerStreamPeer::SendResponse(promised_stream);
        }

        TEST_P(QuicSimpleServerStreamTest, SendResponseWithValidHeaders)
        {
            // Add a request and response with valid headers.
            SpdyHeaderBlock* request_headers = stream_->mutable_headers();
            (*request_headers)[":path"] = "/bar";
            (*request_headers)[":authority"] = "www.google.com";
            (*request_headers)[":version"] = "HTTP/1.1";
            (*request_headers)[":method"] = "GET";

            response_headers_[":version"] = "HTTP/1.1";
            response_headers_[":status"] = "200";
            response_headers_["content-length"] = "5";
            string body = "Yummm";
            QuicInMemoryCache::GetInstance()->AddResponse(
                "www.google.com", "/bar", std::move(response_headers_), body);
            stream_->set_fin_received(true);

            InSequence s;
            EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, nullptr));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(1)
                .WillOnce(Return(QuicConsumedData(body.length(), true)));

            QuicSimpleServerStreamPeer::SendResponse(stream_);
            EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
            EXPECT_TRUE(stream_->reading_stopped());
            EXPECT_TRUE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest, SendReponseWithPushResources)
        {
            // Tests that if a reponse has push resources to be send, SendResponse() will
            // call PromisePushResources() to handle these resources.

            // Add a request and response with valid headers into cache.
            string host = "www.google.com";
            string request_path = "/foo";
            string body = "Yummm";
            string url = host + "/bar";
            QuicInMemoryCache::ServerPushInfo push_info(GURL(url), SpdyHeaderBlock(),
                kDefaultPriority, "Push body");
            std::list<QuicInMemoryCache::ServerPushInfo> push_resources;
            push_resources.push_back(push_info);
            QuicInMemoryCache::GetInstance()->AddSimpleResponseWithServerPushResources(
                host, request_path, 200, body, push_resources);

            SpdyHeaderBlock* request_headers = stream_->mutable_headers();
            (*request_headers)[":path"] = request_path;
            (*request_headers)[":authority"] = host;
            (*request_headers)[":version"] = "HTTP/1.1";
            (*request_headers)[":method"] = "GET";

            stream_->set_fin_received(true);
            InSequence s;
            EXPECT_CALL(session_,
                PromisePushResourcesMock(host + request_path, _,
                    ::net::test::kClientDataStreamId1, _));
            EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, nullptr));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(1)
                .WillOnce(Return(QuicConsumedData(body.length(), true)));
            QuicSimpleServerStreamPeer::SendResponse(stream_);
            EXPECT_EQ(*request_headers, session_.original_request_headers_);
        }

        TEST_P(QuicSimpleServerStreamTest, PushResponseOnClientInitiatedStream)
        {
            // Calling PushResponse() on a client initialted stream is never supposed to
            // happen.
            EXPECT_DFATAL(stream_->PushResponse(SpdyHeaderBlock()),
                "Client initiated stream"
                " shouldn't be used as promised stream.");
        }

        TEST_P(QuicSimpleServerStreamTest, PushResponseOnServerInitiatedStream)
        {
            // Tests that PushResponse() should take the given headers as request headers
            // and fetch response from cache, and send it out.

            // Create a stream with even stream id and test against this stream.
            const QuicStreamId kServerInitiatedStreamId = 2;
            // Create a server initiated stream and pass it to session_.
            QuicSimpleServerStreamPeer* server_initiated_stream = new QuicSimpleServerStreamPeer(kServerInitiatedStreamId, &session_);
            session_.ActivateStream(server_initiated_stream);

            const string kHost = "www.foo.com";
            const string kPath = "/bar";
            SpdyHeaderBlock headers;
            headers[":path"] = kPath;
            headers[":authority"] = kHost;
            headers[":version"] = "HTTP/1.1";
            headers[":method"] = "GET";

            response_headers_[":version"] = "HTTP/1.1";
            response_headers_[":status"] = "200";
            response_headers_["content-length"] = "5";
            const string kBody = "Hello";
            QuicInMemoryCache::GetInstance()->AddResponse(
                kHost, kPath, std::move(response_headers_), kBody);

            // Call PushResponse() should trigger stream to fetch response from cache
            // and send it back.
            EXPECT_CALL(session_,
                WriteHeadersMock(kServerInitiatedStreamId, _, false,
                    server_initiated_stream->priority(), nullptr));
            EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, _, _, _, _))
                .Times(1)
                .WillOnce(Return(QuicConsumedData(kBody.size(), true)));
            server_initiated_stream->PushResponse(std::move(headers));
            EXPECT_EQ(kPath, QuicSimpleServerStreamPeer::headers(server_initiated_stream)[":path"].as_string());
            EXPECT_EQ("GET", QuicSimpleServerStreamPeer::headers(server_initiated_stream)[":method"].as_string());
        }

        TEST_P(QuicSimpleServerStreamTest, TestSendErrorResponse)
        {
            EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);

            stream_->set_fin_received(true);

            InSequence s;
            EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(1)
                .WillOnce(Return(QuicConsumedData(3, true)));

            QuicSimpleServerStreamPeer::SendErrorResponse(stream_);
            EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
            EXPECT_TRUE(stream_->reading_stopped());
            EXPECT_TRUE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest, InvalidMultipleContentLength)
        {
            EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);

            SpdyHeaderBlock request_headers;
            // \000 is a way to write the null byte when followed by a literal digit.
            request_headers["content-length"] = StringPiece("11\00012", 5);

            headers_string_ = SpdyUtils::SerializeUncompressedHeaders(request_headers);

            EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(AnyNumber())
                .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
            stream_->OnStreamHeaders(headers_string_);
            stream_->OnStreamHeadersComplete(true, headers_string_.size());

            EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream_));
            EXPECT_TRUE(stream_->reading_stopped());
            EXPECT_TRUE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest, InvalidLeadingNullContentLength)
        {
            EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);

            SpdyHeaderBlock request_headers;
            // \000 is a way to write the null byte when followed by a literal digit.
            request_headers["content-length"] = StringPiece("\00012", 3);

            headers_string_ = SpdyUtils::SerializeUncompressedHeaders(request_headers);

            EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(AnyNumber())
                .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
            stream_->OnStreamHeaders(headers_string_);
            stream_->OnStreamHeadersComplete(true, headers_string_.size());

            EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream_));
            EXPECT_TRUE(stream_->reading_stopped());
            EXPECT_TRUE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest, ValidMultipleContentLength)
        {
            SpdyHeaderBlock request_headers;
            // \000 is a way to write the null byte when followed by a literal digit.
            request_headers["content-length"] = StringPiece("11\00011", 5);

            headers_string_ = SpdyUtils::SerializeUncompressedHeaders(request_headers);

            stream_->OnStreamHeaders(headers_string_);
            stream_->OnStreamHeadersComplete(false, headers_string_.size());

            EXPECT_EQ(11, QuicSimpleServerStreamPeer::content_length(stream_));
            EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
            EXPECT_FALSE(stream_->reading_stopped());
            EXPECT_FALSE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorWithEarlyResponse)
        {
            InSequence s;
            EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, nullptr));
            EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
                .Times(1)
                .WillOnce(Return(QuicConsumedData(3, true)));
            if (GetParam() > QUIC_VERSION_28) {
                EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
            } else {
                EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
            }
            EXPECT_FALSE(stream_->fin_received());
            QuicSimpleServerStreamPeer::SendErrorResponse(stream_);
            EXPECT_TRUE(stream_->reading_stopped());
            EXPECT_TRUE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest,
            DoNotSendQuicRstStreamNoErrorWithRstReceived)
        {
            InSequence s;
            EXPECT_FALSE(stream_->reading_stopped());

            EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
            EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1);
            QuicRstStreamFrame rst_frame(stream_->id(), QUIC_STREAM_CANCELLED, 1234);
            stream_->OnStreamReset(rst_frame);

            EXPECT_TRUE(stream_->reading_stopped());
            EXPECT_TRUE(stream_->write_side_closed());
        }

        TEST_P(QuicSimpleServerStreamTest, InvalidHeadersWithFin)
        {
            char arr[] = {
                0x3a, 0x68, 0x6f, 0x73, // :hos
                0x74, 0x00, 0x00, 0x00, // t...
                0x00, 0x00, 0x00, 0x00, // ....
                0x07, 0x3a, 0x6d, 0x65, // .:me
                0x74, 0x68, 0x6f, 0x64, // thod
                0x00, 0x00, 0x00, 0x03, // ....
                0x47, 0x45, 0x54, 0x00, // GET.
                0x00, 0x00, 0x05, 0x3a, // ...:
                0x70, 0x61, 0x74, 0x68, // path
                0x00, 0x00, 0x00, 0x04, // ....
                0x2f, 0x66, 0x6f, 0x6f, // /foo
                0x00, 0x00, 0x00, 0x07, // ....
                0x3a, 0x73, 0x63, 0x68, // :sch
                0x65, 0x6d, 0x65, 0x00, // eme.
                0x00, 0x00, 0x00, 0x00, // ....
                0x00, 0x00, 0x08, 0x3a, // ...:
                0x76, 0x65, 0x72, 0x73, // vers
                '\x96', 0x6f, 0x6e, 0x00, // <i(69)>on.
                0x00, 0x00, 0x08, 0x48, // ...H
                0x54, 0x54, 0x50, 0x2f, // TTP/
                0x31, 0x2e, 0x31, // 1.1
            };
            StringPiece data(arr, arraysize(arr));
            QuicStreamFrame frame(stream_->id(), true, 0, data);
            // Verify that we don't crash when we get a invalid headers in stream frame.
            stream_->OnStreamFrame(frame);
        }

    } // namespace
} // namespace test
} // namespace net
